package framework.partitions;

import org.openqa.selenium.By;

import framework.BaseForm;
import framework.catalog.CatalogWithTreeForm;
import framework.elements.BaseElement;
import framework.elements.ComboBox;
import framework.elements.Label;
import framework.elements.Link;
import framework.elements.TextBox;

/** Базовый класс для разделов.
 */
public class BasePartition extends BaseForm{

	/**
	 * @deprecated используйте лучше {@link #BasePartition(String tbodyTemp, String idOrClass, String title)}
	 * Базовый конструктор
	 * @param title название формы
	 * @param idOfForm id формы с разделом
	 */
	public BasePartition(String title, String idOfForm) {
		super(By.xpath(String.format(HEAD_LOCATOR_TEMPLATE, title)), title);
		formId = idOfForm;
		header = title;
		tbodyTemplate = "//form[@id='%s']/table[%s]/tbody";
		tableIndexTemplate = "//form[@id='%s']/table[%s]/caption/span[@class='dhead']/p[contains(.,'%s')]";
	}

	/** Конструктор
	 * @param tbodyTemp например "//div[@class='%s']/table[%s]/tbody"
	 * @param idOrClass id или класс элемента, содержащего таблицы с разделами
	 * @param title название раздела
	 */
	public BasePartition(String tbodyTemp, String idOrClass, String title){
		super(By.xpath(String.format(HEAD_LOCATOR_TEMPLATE, title)), title);
		this.tbodyTemplate = tbodyTemp;
		formId = idOrClass;
		header = title;
		tableIndexTemplate = tbodyTemplate.replace("/tbody","") + "/caption/span[@class='dhead']/p[contains(.,'%s')]";
		String locator = tableIndexTemplate.replace("/table[%s]", "/form//table");
		Label l = new Label(By.xpath(String.format(locator, idOrClass, header)), "Раздел " + header);
		if(l.isPresent()){
			tableIndexTemplate = locator.replace("/form//table", "/form/table[%s]");
			tbodyTemplate = tbodyTemp.replace("/table[%s]", "/form/table[%s]");
		}
	}
	private final int maxPartFieldsCount = 15;
	private static final String INPUT_ADDON = "/input";
	private static final String TEXTAREA_ADDON = "/textarea";
	private static final String SELECT_ADDON = "/select";
	private static final String HEAD_LOCATOR_TEMPLATE = "//table/caption/span[@class='dhead']/p[contains(.,'%s')]";
	private String tableIndexTemplate;
	private final int maxCountOfPartitions = 6;
	private String tbodyTemplate;
	private final String recordTemplate = "/tr[%s]/td[2]";
	private String tableContentTemplate = "";
	private Boolean initialize = false;
	private final String formId;
	private final String header;
	// Локаторы открытия справочников
	private static final String OKDP_LOCATOR = "/img[contains(@onclick,'chooseOkdp.html')]";
	private static final String OKVED_LOCATOR = "/img[contains(@onclick,'chooseOkved.html')]";

	/** Возвращает локатор "/img[contains(@onclick,'chooseOkdp.html')]"
	 * @return "/img[contains(@onclick,'chooseOkdp.html')]"
	 */
	public static String getOpenOkdpImgAddon(){
		return OKDP_LOCATOR;
	}

	/** Возвращает локатор "/img[contains(@onclick,'chooseOkved.html')]"
	 * @return "/img[contains(@onclick,'chooseOkved.html')]"
	 */
	public static String getOpenOkvedImgAddon(){
		return OKVED_LOCATOR;
	}

	/** Инициализирует раздел
	 */
	private void initialize(){
		if(!initialize){
			tableContentTemplate = String.format(tbodyTemplate, formId, getTableIndex());
			initialize = true;
		}
	}

	/** Возвращает "/input"
	 * @return "/input"
	 */
	public static String getInputAddon(){
		return INPUT_ADDON;
	}

	/** Возвращает "/textarea"
	 * @return "/textarea"
	 */
	public static String getTextareaAddon(){
		return TEXTAREA_ADDON;
	}

	/** Возвращает "/select"
	 * @return "/select"
	 */
	public static String getSelectAddon(){
		return SELECT_ADDON;
	}

	/**  Возвращает шаблон локатора к названию раздела
	 * @return шаблон
	 */
	protected static String getHeaderLocatorTemplate(){
		return HEAD_LOCATOR_TEMPLATE;
	}

	/** Возвращает номер таблицы, в которой находится раздел
	 * @return номер таблицы
	 */
	protected Integer getTableIndex(){
		Label l;
		for(int i = 1; i < maxCountOfPartitions; i++){
			l = new Label(By.xpath(String.format(tableIndexTemplate, formId, i,header)), "Раздел");
			if(l.isPresent()){
				return i;
			}
		}
		logger.fatal("Не удалось найти раздел " + header);
		return 0;
	}

	/** @deprecated используйте лучше {@link #getText(Integer, String, String)}}
	 * Возвращает значение поля
	 * @param field номер поля
	 * @param subField номер под-поля(если есть, если нет то 0)
	 * @param isSubfield есть под поле?
	 * @param fieldName наименование поля
	 * @return значение поля
	 */
	public String getText(Integer field, Integer subField, Boolean isSubfield, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field);
		if(isSubfield){
			locator = locator + "/p[" + subField +"]";
		}
		Label l = new Label(By.xpath(locator), fieldName);
		l.waitAndAssertIsPresent();
		String text = l.getText();
		logger.info("Поле " + fieldName + " содержит значение: " + text);
		return text;
	}

	/** Возвращает значение поля
	 * @param field номер поля
	 * @param addonForCell дополнение к локатору для поля, например "/input" или "/textarea"
	 * @param fieldName наименование поля
	 * @return значение поля
	 */
	public String getText(Integer field, String addonForCell, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + addonForCell;
		Label l = new Label(By.xpath(locator), fieldName);
		l = (Label)getElementByAddonLocator(addonForCell, l, fieldName);
		l.waitAndAssertIsPresent();
		String text = l.getText();
		logger.info("Поле " + fieldName + " содержит значение: " + text);
		return text;
	}

	/** Возвращает значение поля с определенным названием
	 * @param fieldName наименование поля
	 * @param addonForFieldValue дополнительный локатор к ячейке с текстом,
	 * например "/span"
	 * @param addonForFieldName дополнительный локатор к ячейке с названием поля
	 * @return значение поля
	 */
	public String getText(String fieldName, String addonForFieldName, String addonForFieldValue){
		initialize();
		Label lN, lV;
		for(int i = 1; i <= maxPartFieldsCount; i++){
			lN = new Label(By.xpath(tableContentTemplate + "/tr[" + i + "]/td[1]" + addonForFieldName), fieldName);
			if(lN.isPresent() && (lN.getText().equals(fieldName) || lN.getText().equals(fieldName.replace("Полное н", "Н")))){
				lV = new Label(By.xpath(tableContentTemplate + "/tr[" + i + "]/td[2]" + addonForFieldValue), "Значение поля " + fieldName);
				lV.waitAndAssertIsPresent();
				String text = lV.getText();
				logger.info("Поле " + fieldName + " содержит текст: " + text);
				return text;
			}
		}
		logger.fatal("Поле " + fieldName + " отсутсвует в разделе " + title);
		return null;
	}

	/** Возвращает значение поля с определенным названием
	 * @param fieldName наименование поля
	 * @param addonForFieldValue дополнительный локатор к ячейке с текстом,
	 * например "/span"
	 * @param addonForFieldName дополнительный локатор к ячейке с названием поля
	 * @param expected ожидаемое значение поля
	 */
	public void assertTextInField(String fieldName, String addonForFieldName, String addonForFieldValue, String expected){
		jassert.assertText(fieldName, expected, getText(fieldName, addonForFieldName, addonForFieldValue), false);
	}

	/** Вводит значение в поле
	 * @param field поле
	 * @param addonForLocator дополнение к локатору для поля, например "/input" или "/textarea"
	 * @param value вводимое значение
	 * @param fieldName название поля
	 */
	public void setValue(Integer field, String addonForLocator, String value, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + addonForLocator;
		TextBox txb = new TextBox(By.xpath(locator), fieldName);
		txb = (TextBox)getElementByAddonLocator(addonForLocator, txb, fieldName);
		txb.setText(value);
	}

	/** Выбирает значение из комбобокса
	 * @param field номер поля
	 * @param addonLocator дополнение к локатору (например /input)
	 * @param value выбираемое значение
	 * @param fieldName название поля
	 */
	public void selectFromCmb(Integer field, String addonLocator, String value, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + addonLocator;
		ComboBox cmb = new ComboBox(By.xpath(locator), fieldName);
		cmb = (ComboBox)getElementByAddonLocator(addonLocator, cmb, fieldName);
		cmb.selectByText(value);
	}

	/** Выбирает первое доступное значение из комбобокса
	 * @param field номер поля
	 * @param addonLocator дополнение к локатору (например /input)
	 * @param fieldName название поля
	 * @return выбранное значение
	 */
	public String selectFromCmb(Integer field, String addonLocator, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + addonLocator;
		ComboBox cmb = new ComboBox(By.xpath(locator), fieldName);
		cmb = (ComboBox) getElementByAddonLocator(addonLocator, cmb, fieldName);
		return cmb.selectRandomValue();
	}

	/** Проверяет есть ли элементс таким локатором, если нет то использует в качестве локатора addonLocator
	 * @param addonLocator локатор к полю, например "/input[@id='ID']"
	 * @param element элемент
	 * @param fieldName наименование элемента
	 * @return элемент
	 */
	private BaseElement getElementByAddonLocator(String addonLocator, BaseElement element, String fieldName){
		if(!element.isPresent()){
			String locator = "/" + addonLocator;
			if(element instanceof Link){
				element = new Link(By.xpath(locator), fieldName);
			}else if(element instanceof Label){
				element = new Label(By.xpath(locator), fieldName);
			}else if(element instanceof ComboBox){
				element = new ComboBox(By.xpath(locator), fieldName);
			}else if(element instanceof TextBox){
				element = new TextBox(By.xpath(locator), fieldName);
			}
		}
		return element;
	}

	/**@deprecated лучше используйте {@link #assertText(String, Integer, String, String)}}
	 * Проверяет текст поля
	 * @param expected ожидаемое значение
	 * @param field номер поля
	 * @param subField номер подполя
	 * @param isSubfield есть подполе?
	 * @param fieldName наименование поля
	 */
	public void assertText(String expected, Integer field, Integer subField, Boolean isSubfield, String fieldName){
		String text = getText(field, subField, isSubfield, fieldName);
		jassert.assertText(fieldName, expected, text, false);
	}

	/** Проверяет текст поля
	 * @param expected ожидаемое значение
	 * @param field номер поля
	 * @param addonForCell дополнение к локатору, например "/input" или "/textarea"
	 * @param fieldName наименование поля
	 */
	public void assertText(String expected, Integer field, String addonForCell, String fieldName){
		String text = getText(field, addonForCell, fieldName);
		jassert.assertText(fieldName, expected, text, false);
	}

	/** Проверяет значение аттрибута "value"
	 * @param expected ожидаемое значение
	 * @param field номер поля
	 * @param addonForCell дополнение к локатору, например "/input" или "/textarea"
	 * @param fieldName наименование поля
	 */
	public void assertValue(String expected, Integer field, String addonForCell, String fieldName){
		String text = getValue(field, addonForCell, fieldName);
		jassert.assertText(fieldName, expected, text, false);
	}

	/** Получает значение аттрибута "value"
	 * @param field номер поля
	 * @param addonForCell дополнение к локатору, например "/input" или "/textarea"
	 * @param fieldName название поля
	 * @return значение аттрибута "value"
	 */
	public String getValue(int field, String addonForCell, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + addonForCell;
		Label l = new Label(By.xpath(locator), fieldName);
		l = (Label)getElementByAddonLocator(addonForCell, l, fieldName);
		String text = l.getValue();
		logger.info("Поле " + fieldName + " содержит значение: " + text);
		return text;
	}

	@Override
	public void assertIsOpen() {
		Label elem = new Label(titleLocator, title);
		try {
			elem.waitAndAssertIsPresent();
			//info(String.format("Раздел '%1$s' отображен", this.title));
		} catch (Throwable e) {
			fatal(String.format("Раздел '%1$s' не отображен", this.title));
		}
	}

	/** Возвращает название раздела
	 * @return название раздела
	 */
	public String getPartitionName(){
		return header;
	}

	/** Открывает справочник с деревом
	 * @param field номер строки в которой находится иконка для открытия
	 * @param imgLocator локатор иконки, например "/img[contains(@onclick,'chooseOkdp.html')]"
	 * или "/div/img[contains(@onclick,'chooseOkdp.html')]"
	 * @param catalogName название открываемого справочника
	 * @return справочник с деревом
	 */
	public CatalogWithTreeForm openCatalogWithTree(int field, String imgLocator, String catalogName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + imgLocator;
		Link l = new Link(By.xpath(locator), "Открыть справочник " + catalogName);
		l = (Link) getElementByAddonLocator(imgLocator, l, "Открыть справочник " + catalogName);
		l.clickAndRepeatIfNewWindowNotAppeared(2);
		return new CatalogWithTreeForm();
	}

	/** Проверяет, что поле недоступно для редактирования
	 * @param field номер поля в разделе
	 * @param addonForCell дополнение к локатору ячейки таблицы /td. Например /input
	 * @param fieldName наимевание поля
	 */
	public void assertFieldIsDisabled(int field, String addonForCell, String fieldName){
		initialize();
		String locator = tableContentTemplate + String.format(recordTemplate, field) + addonForCell;
		Label l = new Label(By.xpath(locator), fieldName);
		l = (Label)getElementByAddonLocator(addonForCell, l, fieldName);
		String disabled = l.getAttribute("disabled");
		if(disabled.equals("false")){
			disabled = l.getAttribute("readonly");
		}
		if(disabled.equals("") || disabled.equals("disabled") || disabled.equals("true")){
			disabled = "disabled";
		}
		jassert.assertText("Атрибут 'disabled' поля " + fieldName, "disabled", disabled, true);
	}
}
